package cn.moefly.common.utils;

import lombok.extern.slf4j.Slf4j;

import java.util.function.BiConsumer;


@Slf4j
public abstract class SpinTaskUtils {

    static ThreadLocal<Integer> sExceptionTimes = ThreadLocal.withInitial(()-> 0);


    /**
     * 避免一个循环任务因为错误而把log给占满，当出现自旋错误时，只在前5次打印log，并在随后每100次重新打印log
     * 当有一次任务重新完成后，重置exception计数，并打印日志
     * 如果需要停止并退出当前线程，请在 throwableHandler 中调用 Thread.currentThread().interrupt();
     *
     * @param throwableHandler 1st Args is the exception, 2nd is exception repeat times
     */
    public static void runSpinTask(Runnable spinTask,
                            BiConsumer<Throwable,Integer> throwableHandler){
        while (!Thread.currentThread().isInterrupted()) {
            try {
                spinTask.run();
                if (sExceptionTimes.get() > 0){
                    var threadName = Thread.currentThread().getName();
                    log.info("{} has recover",threadName);
                    sExceptionTimes.set(0);
                }
            } catch(Throwable t) {
                Integer times = sExceptionTimes.get();
                throwableHandler.accept(t,times);
                if (times < 5 || times % 100 == 0){
                    var threadName = Thread.currentThread().getName();
                    log.error("{} catch runtimeException or throwable. Continuousexception times: {}",threadName,times);
                }
                sExceptionTimes.set(times+1);
            }
        }

    }
}
